# coding=utf-8

import inspect
from functools import wraps
from flask import g, redirect, url_for, request, session


def login_required(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        if g.user is None:
            return redirect(url_for('over.handlers.auth.login', next=request.url))
        return f(*args, **kwargs)

    return wrapper


class Router(object):
    def __init__(self):
        self.cls = None
        self.class_url = None
        self.route_methods = {}  # method_name: url, methods, view tuple
        self.func_routers = {}  # routers的时候,函数先进行处理

    @classmethod
    def flask_view(cls, router_class, method):
        @login_required
        def view(*args, **kwargs):
            class_view = view.class_view
            self = class_view(*class_view._args, **class_view._kwargs)
            return method(self, *args, **kwargs)

        view.class_view = router_class

        names = []

        if hasattr(router_class, '__router_name__'):
            name = router_class.__router_name__
        else:
            name = router_class.__name__.lower()
        names.append(name)
        names.append(method.__name__)

        view.__name__ = '.'.join(names)
        view.__doc__ = method.__doc__
        view.__module__ = method.__module__

        if hasattr(method, 'methods'):
            methods = method.methods
        else:
            methods = router_class.methods
        view.methods = methods

        print(dir(view))

        return view

    def _route(self, url, cls):
        if url.endswith('/'):
            url = url.rstrip('/')

        for name in dir(cls):
            if name.startswith('_'):
                continue

            method = getattr(cls, name)
            if method is not None:
                view = self.flask_view(cls, method)
                u = url + '/' + '-'.join(name.split('_'))
                self.route_methods[name] = (u, view)

        for name in self.func_routers:
            u, methods = self.func_routers[name]
            u = url + u
            _, view = self.route_methods[name]
            if methods is not None:
                view.methods = methods

            self.route_methods[name] = (u, view)

    def route(self, url, methods=None, *args, **kwargs):
        def inner(cls):
            if inspect.isclass(cls):
                cls.methods = methods
                self.class_url = url
                self._route(url, cls)
                cls._args = args
                cls._kwargs = kwargs

            if inspect.isfunction(cls):
                func_name = cls.__name__
                cls.methods = methods
                self.func_routers[func_name] = (url, methods)

            return cls

        return inner

    def __call__(self, *args, **kwargs):
        return self.route(*args, **kwargs)

    # def __call__(self, rule, methods=None, *args, **kwargs):
    #     def decorator(cls):
    #         @wraps(cls)
    #         def inner(*_args, **_kwargs):
    #             return cls(*_args, **_kwargs)
    #
    #         if inspect.isclass(cls):
    #             cls.methods = methods
    #             self.class_url = rule
    #             self._route(rule, cls)
    #             cls._args = args
    #             cls._kwargs = kwargs
    #
    #         if inspect.isfunction(cls):
    #             func_name = cls.__name__
    #             cls.methods = methods
    #             self.func_routers[func_name] = (rule, methods)
    #
    #         return inner
    #
    #     return decorator

    def register_url_rules(self, mod):
        for name in self.route_methods:
            url, view = self.route_methods[name]
            mod.add_url_rule(url, view_func=view)

